﻿
namespace TestFsWeb

open System
open System.Net
open System.IO

type SimpleHttpServer(prefix)=
    
    // ********************************** primary constructor
    do
        if not HttpListener.IsSupported then
            failwith "HttpListener is NOT supported by OS"

    let m_listener = new HttpListener()
    
    do
        m_listener.Prefixes.Add prefix

    // ********************************** private helpers
    let print_request (request : HttpListenerRequest) =
        printfn "%s %s HTTP/1.1" request.HttpMethod request.RawUrl
        printfn "Accept: %s" <| String.Join(",",request.AcceptTypes)
        printfn "Accept-Language: %s" <| String.Join(",",request.UserLanguages)
        printfn "User-Agent: %s" request.UserAgent        
        printfn "Connection: %s" <| if request.KeepAlive then "Keep-Alive" else "close"
        printfn "Host: %s" request.UserHostName
        printfn "Cache-Control: %s" request.Headers.["Cache-Control"]

        if request.HasEntityBody then
            use reader = new StreamReader(request.InputStream,request.ContentEncoding)
            printfn "body: %s" (reader.ReadToEnd())
        else
            printfn "no body included in the request"

    let send_response (response : HttpListenerResponse) =
        try
            let content = "<html><head><title>Server Response</title></head><body>hello web!</body></html>"
            let binImage = System.Text.Encoding.UTF8.GetBytes(content)

            response.ContentLength64 <- int64(binImage.Length)
            response.ContentType <- "text/html; charset=UTF-8"
            response.StatusCode <- int HttpStatusCode.OK

            // close the output stream will also flush the content out
            use stream = response.OutputStream 
            stream.Write(binImage,0,binImage.Length)
        finally
            // from MSDN, it just close the output stream
            // and doesn't close the response explicitly, maybe that's already enough
            (response :> IDisposable).Dispose()

    // ********************************** members
    member this.Run() =
        m_listener.Start()
        printfn "server started, ......"

        let rec loop counter =
            let context = m_listener.GetContext()
            printfn "\n################### %d-th request" counter

            context.Request |> print_request
            context.Response |> send_response

            loop (counter+1)

        loop 1

    interface IDisposable with
        member this.Dispose() =
            m_listener.Stop()
            m_listener.Close()

module TestSimpleHttpServer =
    let main() =
        // !!!!! the URL must end with slash
        // otherwise, it will throw: Unhandled Exception: System.ArgumentException: 
        // Only Uri prefixes ending in '/' are allowed.
        use server = new SimpleHttpServer("http://localhost:50000/")
        server.Run()



    
